"use strict";

var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");

require("core-js/modules/es.array.iterator");

require("core-js/modules/es.array-buffer.slice");

require("core-js/modules/es.object.to-string");

require("core-js/modules/es.typed-array.uint8-array");

require("core-js/modules/es.typed-array.copy-within");

require("core-js/modules/es.typed-array.every");

require("core-js/modules/es.typed-array.fill");

require("core-js/modules/es.typed-array.filter");

require("core-js/modules/es.typed-array.find");

require("core-js/modules/es.typed-array.find-index");

require("core-js/modules/es.typed-array.for-each");

require("core-js/modules/es.typed-array.includes");

require("core-js/modules/es.typed-array.index-of");

require("core-js/modules/es.typed-array.iterator");

require("core-js/modules/es.typed-array.join");

require("core-js/modules/es.typed-array.last-index-of");

require("core-js/modules/es.typed-array.map");

require("core-js/modules/es.typed-array.reduce");

require("core-js/modules/es.typed-array.reduce-right");

require("core-js/modules/es.typed-array.reverse");

require("core-js/modules/es.typed-array.set");

require("core-js/modules/es.typed-array.slice");

require("core-js/modules/es.typed-array.some");

require("core-js/modules/es.typed-array.sort");

require("core-js/modules/es.typed-array.subarray");

require("core-js/modules/es.typed-array.to-locale-string");

require("core-js/modules/es.typed-array.to-string");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.SchemaFactory = SchemaFactory;
exports.default = void 0;

var _ = require("../");

var uint8 = _interopRequireWildcard(require("../parsers/uint8"));

function SchemaFactory(_ref) {
  var readByte = _ref.readByte,
      peekByte = _ref.peekByte,
      readBytes = _ref.readBytes,
      peekBytes = _ref.peekBytes,
      readString = _ref.readString,
      readUnsigned = _ref.readUnsigned,
      readArray = _ref.readArray,
      readBits = _ref.readBits;
  // a set of 0x00 terminated subblocks
  var subBlocksSchema = {
    blocks: function blocks(stream) {
      var terminator = 0x00;
      var chunks = [];
      var total = 0;

      var next = function next() {
        return readByte()(stream).then(function (size) {
          if (size == terminator) {
            return chunks;
          } else {
            return readBytes(size)(stream).then(function (bytes) {
              chunks.push(bytes);
              total += size;
            }).then(next);
          }
        });
      };

      return next().then(function () {
        var result = new Uint8Array(total);
        var offset = 0;

        for (var i = 0; i < chunks.length; i++) {
          result.set(chunks[i], offset);
          offset += chunks[i].length;
        }

        return result;
      });
    }
  }; // global control extension

  var gceSchema = (0, _.conditional)({
    gce: [{
      codes: readBytes(2)
    }, {
      byteSize: readByte()
    }, {
      extras: readBits({
        future: {
          index: 0,
          length: 3
        },
        disposal: {
          index: 3,
          length: 3
        },
        userInput: {
          index: 6
        },
        transparentColorGiven: {
          index: 7
        }
      })
    }, {
      delay: readUnsigned(true)
    }, {
      transparentColorIndex: readByte()
    }, {
      terminator: readByte()
    }]
  }, function (stream) {
    return peekBytes(2)(stream).then(function (codes) {
      return codes[0] === 0x21 && codes[1] === 0xf9;
    });
  }); // image pipeline block

  var imageSchema = (0, _.conditional)({
    image: [{
      code: readByte()
    }, {
      descriptor: [{
        left: readUnsigned(true)
      }, {
        top: readUnsigned(true)
      }, {
        width: readUnsigned(true)
      }, {
        height: readUnsigned(true)
      }, {
        lct: readBits({
          exists: {
            index: 0
          },
          interlaced: {
            index: 1
          },
          sort: {
            index: 2
          },
          future: {
            index: 3,
            length: 2
          },
          size: {
            index: 5,
            length: 3
          }
        })
      }]
    }, (0, _.conditional)({
      lct: readArray(3, function (stream, result, parent) {
        return Math.pow(2, parent.descriptor.lct.size + 1);
      })
    }, function (stream, result, parent) {
      return parent.descriptor.lct.exists;
    }), {
      data: [{
        minCodeSize: readByte()
      }, subBlocksSchema]
    }]
  }, function (stream) {
    return peekByte()(stream).then(function (v) {
      return v === 0x2c;
    });
  }); // plain text block

  var textSchema = (0, _.conditional)({
    text: [{
      codes: readBytes(2)
    }, {
      blockSize: readByte()
    }, {
      preData: function preData(stream, result, parent) {
        return readBytes(parent.text.blockSize)(stream);
      }
    }, subBlocksSchema]
  }, function (stream) {
    return peekBytes(2)(stream).then(function (codes) {
      return codes[0] === 0x21 && codes[1] === 0x01;
    });
  }); // application block

  var applicationSchema = (0, _.conditional)({
    application: [{
      codes: readBytes(2)
    }, {
      blockSize: readByte()
    }, {
      id: function id(stream, result, parent) {
        return readString(parent.blockSize)(stream);
      }
    }, subBlocksSchema]
  }, function (stream) {
    return peekBytes(2)(stream).then(function (codes) {
      return codes[0] === 0x21 && codes[1] === 0xff;
    });
  }); // comment block

  var commentSchema = (0, _.conditional)({
    comment: [{
      codes: readBytes(2)
    }, subBlocksSchema]
  }, function (stream) {
    return peekBytes(2)(stream).then(function (codes) {
      return codes[0] === 0x21 && codes[1] === 0xfe;
    });
  });
  var schema = [{
    header: [{
      signature: readString(3)
    }, {
      version: readString(3)
    }]
  }, {
    lsd: [{
      width: readUnsigned(true)
    }, {
      height: readUnsigned(true)
    }, {
      gct: readBits({
        exists: {
          index: 0
        },
        resolution: {
          index: 1,
          length: 3
        },
        sort: {
          index: 4
        },
        size: {
          index: 5,
          length: 3
        }
      })
    }, {
      backgroundColorIndex: readByte()
    }, {
      pixelAspectRatio: readByte()
    }]
  }, (0, _.conditional)({
    gct: readArray(3, function (stream, result) {
      return Math.pow(2, result.lsd.gct.size + 1);
    })
  }, function (stream, result) {
    return result.lsd.gct.exists;
  }), // content frames
  {
    frames: (0, _.loop)([gceSchema, applicationSchema, commentSchema, imageSchema, textSchema], function (stream) {
      return peekByte()(stream).then(function (nextCode) {
        return (// rather than check for a terminator, we should check for the existence
          // of an ext or image block to avoid infinite loops
          //var terminator = 0x3B;
          //return nextCode !== terminator;
          nextCode === 0x21 || nextCode === 0x2c
        );
      });
    })
  }];
  return schema;
}

var _default = SchemaFactory(uint8);

exports.default = _default;